﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using UnityMultiPlayerGameServer.Data;
using UnityMultiPlayerGameServer.Manager;
using GameProtocol;
using Google.Protobuf;
using System.Net;

namespace UnityMultiPlayerGameServer.Clients
{
    internal class Client
    {
        private Socket socket;

        /// <summary>
        /// 远程主机IP  用于UDP处理
        /// </summary>
        private EndPoint remoteIP;
        
        /// <summary>
        /// 记录用户信息
        /// </summary>
        public UserInfo userInfo;
        
        /// <summary>
        /// 记录和处理接收的消息
        /// </summary>
        private Message message;

        /// <summary>
        /// 返回当前客户端内用户是否成功登录
        /// </summary>
        private bool isLogin = false;

        #region 属性
        public Socket Socket { get => socket; }
        public bool IsLogin { get => isLogin; set => isLogin = value; }
        public EndPoint RemoteIP { get => remoteIP; set => remoteIP = value; }
        #endregion

        public Client(Socket socket)
        {
            this.socket = socket;
            userInfo = new UserInfo();
            userInfo.CharacterChossedID = -1;
            message = new Message();
            this.socket.BeginReceive(message.buffer, message.startIndex, message.buffer.Length, SocketFlags.None, ReceiveCallback, null);
            Console.WriteLine("client: "+ socket.RemoteEndPoint + " was created");         
        }

        public void RestUserInfoState()
        {
            userInfo.IsPrepared = false;
            userInfo.CharacterChossedID = -1;
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="pack"></param>
        public void Send(GamePack pack)
        {

            if (socket == null || socket.Connected == false)
            {
                //Console.WriteLine("send false");
                return;
            }
            try
            {
                //打包数据
                byte[] buffer = Message.PackData(pack);

                SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                eventArgs.SetBuffer(buffer, 0, buffer.Length);
                eventArgs.Completed += (socket, args) =>
                {
                    if (args.SocketError != SocketError.Success)
                    {
                        //print("send fail" + args.SocketError);
                        Close();
                    }
                };
                //Console.WriteLine("send");
                //Console.WriteLine(socket.RemoteEndPoint);
                socket.SendAsync(eventArgs);
            }
            catch (Exception e)
            {
                Console.WriteLine("Client:" + socket.RemoteEndPoint.Serialize().ToString() + " 发送消息时异常：\n" + e.Message);
                Close();
                throw;
            }
        }


        /// <summary>
        /// BeginReceive的回调函数
        /// </summary>
        /// <param name="iar"></param>
        private void ReceiveCallback(IAsyncResult iar)
        {
            try
            {
                if (socket == null || socket.Connected == false) return;

                int receiveLength = this.socket.EndReceive(iar);
                if(receiveLength > 0)
                {
                    HandleReciveBuffer(receiveLength);
                }

                this.socket.BeginReceive(message.buffer, 0, message.buffer.Length, SocketFlags.None, ReceiveCallback, null);
            }
            catch (Exception e)
            {
                
                Console.WriteLine("接收数据时发生错误" + e.Message);
                Close();
                //若客户端异常断开连接，此时需要用return跳出递归二倍速throw，防止卡线程
                //throw;
                return;
            }
        }


        public void Close()
        {
            Console.WriteLine(socket.RemoteEndPoint.Serialize().ToString() + " 断开");
            socket.Shutdown(SocketShutdown.Both);
            socket.Disconnect(false);
            socket.Close();
            socket = null;
        }

        /// <summary>
        /// 处理接收到的byte数组
        /// </summary>
        /// <param name="length"></param>
        private void HandleReciveBuffer(int length)
        {
            message.ReadBuffer(length, this, ControllerManager.Instance.PackHandel);
        }


        
        
        ///////////////////////////////////////////////////////////////////////////////////
        //private byte[] receiveBuffer = new byte[1024];
        //处理分包黏包的缓存数组
        //private byte[] cacheBuffer = new byte[2048];
        //用以表示当前缓存数组中有多少数据
        //private int cacheIndex = 0;

        //private void HandleReciveBuffer(byte[] receiveBytes, int receiveLength)
        //{
        //    //消息体长度
        //    int msgLength = 0;
        //    //当前处理的长度
        //    int nowIndex = 0;

        //    //收到消息时  若有缓存的将当前接收的数组直接拼接到后面
        //    receiveBytes.CopyTo(cacheBuffer, cacheIndex);
        //    //设置当前数组中有多长的数据
        //    cacheIndex += receiveLength;

        //    while (true)
        //    {
        //        msgLength = -1;
        //        if (cacheIndex - nowIndex >= 4)
        //        {
        //            //解析消息长度
        //            msgLength = BitConverter.ToInt32(cacheBuffer, nowIndex);
        //            nowIndex += 4;
        //        }
        //        //判断当前缓存数组内的数据长度是否大于等于消息体长度
        //        if (cacheIndex - nowIndex >= msgLength && msgLength != -1)
        //        {
        //            //若大于则解析消息体
        //            message.SetBuffer(cacheBuffer, nowIndex, msgLength);

        //            nowIndex += msgLength;
        //            if (nowIndex == cacheIndex)
        //            {
        //                cacheIndex = 0;
        //                break;
        //            }
        //        }
        //        else
        //        {
        //            //小于则证明有分包
        //            //如果进行了id和长度的解析 但是没有成功解析消息体 减去nowIndex移动的位置
        //            if (msgLength != -1)
        //            {
        //                nowIndex -= 4;
        //            }
        //            //把剩余没有解析的字节数组内容 移到前面来 用于缓存下次继续解析
        //            Array.Copy(cacheBuffer, nowIndex, cacheBuffer, 0, cacheIndex - nowIndex);
        //            cacheIndex = cacheIndex - nowIndex;
        //            break;
        //        }

        //    }
        //}
        ////////////////////////////////////////////////////////////////////////////////////////////////////////
    }
}
